/**
  ******************************************************************************
  * File Name          : sio_service.c
  * Description        : This file provides code for the configuration
  *                      of the TiSioService instances.
  ******************************************************************************
  * @attention
  * Created by Chen Lu in 20210504
  *
  ******************************************************************************
  */

#include "stdlib.h"
#include "string.h"
#include "main.h"
#include "usart.h"
#include "sio_service.h"

/**
  * @brief  Open a serial input&output service.
  *
  * @note   This function creates a serial input&output service.
  *
  * @retval A serial input&output service instance pointer.
  */
TiSioService * sio_open()
{
	TiSioService *sio = (TiSioService*) malloc(sizeof(TiSioService));
	memset(sio, 0x00, sizeof(TiSioService));
	sio->rxlen = 0;
	sio->txlen= 0;
	memset(sio->rxque, 0x00, BUF_MAX_LENGTH);
	memset(sio->txque, 0x00, BUF_MAX_LENGTH);
	return sio;
}

/**
  * @brief  Close a serial input&output service.
  *
  * @note   This function closes a serial input&output service. Note that in this measure,
  * 		space allocated for serial input&output service instance pointer is freed,
  * 		so it need to be used discreetly!
  *
  * @param  sio		The serial input&output service instance pointer.
  * @retval SIOSERIVCE status.
  */
uint8_t sio_close(TiSioService* sio)
{
	free(sio);
	return SIOSERVICE_OK;
}

/**
  * @brief  Receive a frame through serial input&output service.
  *
  * @note   This function receives a frame through serial input&output service,
  * 		and check whether it conforms to the format we've appointed. If it is, save to serial input&output service,
  * 		otherwise, return 0.
  *
  * @param  sio		The serial input&output service instance pointer.
  * @retval SIOSERIVCE status.
  */
uint8_t sio_recv(TiSioService* sio)
{
	if ((sio->rxlen > 0) && (sio->rxque[sio->rxlen - 2] == 0x0D) && (sio->rxque[sio->rxlen - 1] == 0x0A))
	{
		if ((sio->rxque[0] == 0xFF) && (sio->rxque[1] == 0xFF))
		{
			if (sio->rxque[2] == 0x02)
			{
				if (sio->rxque[4] == (sio->rxlen - 5))
				{
					memcpy(sio->rxbuf,sio->rxque + 5,sio->rxque[4] - 2);
					//sio->rxlen = 0;
					memset(sio->rxque, 0x00, BUF_MAX_LENGTH);
					return SIOSERVICE_OK;
				}
				else
				{
					printf("%s\r\n","Frame length error!");
					sio->rxlen = 0;
					memset(sio->rxque, 0x00, BUF_MAX_LENGTH);
					sio_trans(sio,(uint8_t*)"NACK");
					return SIOSERVICE_ERROR;
				}
			}
			else
			{
				printf("%s\r\n","Frame source destination error!");
				sio->rxlen = 0;
				memset(sio->rxque, 0x00, BUF_MAX_LENGTH);
				sio_trans(sio,(uint8_t*)"NACK");
				return SIOSERVICE_ERROR;
			}
		}
		else
		{
			printf("%s\r\n","Frame head error!");
			sio->rxlen = 0;
			memset(sio->rxque, 0x00, BUF_MAX_LENGTH);
			sio_trans(sio,(uint8_t*)"NACK");
			return SIOSERVICE_ERROR;
		}
	}
	else if (sio->rxlen == 0)
	{
		printf("%s\r\n","Receive nothing!");
		memset(sio->rxque, 0x00, BUF_MAX_LENGTH);
		sio_trans(sio,(uint8_t*)"NACK");
		return 0;
	}
	else
	{
		printf("%s\r\n","Frame rear error!");
		sio->rxlen = 0;
		memset(sio->rxque, 0x00, BUF_MAX_LENGTH);
		sio_trans(sio,(uint8_t*)"NACK");
		return SIOSERVICE_ERROR;
	}
	return SIOSERVICE_OK;
}

/**
  * @brief  Transmit a frame through serial input&output service.
  *
  * @note   This function transmits a frame through serial input&output service.
  *
  * @param  sio		The serial input&output service instance pointer.
  * @param	data	Data to be transmitted.
  * @retval SIOSERIVCE status.
  */
uint8_t sio_trans(TiSioService* sio, uint8_t* data)
{
	sio->txlen = strlen((const char*) data);
	memcpy(sio->txque, data, sio->txlen);
#ifndef DEBUG_MODE
	USART2_TX.len = sio->txlen;
	memcpy(USART2_TX_BUF, sio->txque, sio->txlen);
	/**At first, I used HAL_UART_DMA_Transmit. However, a mistake occurred, in which the program enter
	 * USART_IRQHandler continuously when finishing this measure. I have not figured this problem until now.
	 * So I use HAL_USART_transmit instead, cause this measure will not be used frequently.
	 */
	if (HAL_UART_Transmit(&huart2, (uint8_t*)USART2_TX.p_data, USART2_TX.len,20)!=HAL_OK)
	{
		printf("%s\r\n","SIO transmission error!");
		return SIOSERVICE_ERROR;
	}
	sio->txlen = 0;
	memset(sio->txque,0x00,BUF_MAX_LENGTH);
	USART2_TX.len = 0;
	memset(USART2_TX_BUF,0x00,BUF_MAX_LENGTH);
#endif
#ifdef DEBUG_MODE
	USART1_TX.len = sio->txlen;
	memcpy(USART1_TX_BUF, sio->txque, sio->txlen);
	/**At first, I used HAL_UART_DMA_Transmit. However, a mistake occurred, in which the program enter
	 * USART_IRQHandler continuously when finishing this measure. I have not figured this problem until now.
	 * So I use HAL_USART_transmit instead, cause this measure will not be used frequently.
	 */
	if (HAL_UART_Transmit(&huart1, (uint8_t*)USART1_TX.p_data, USART1_TX.len,20)!=HAL_OK)
	{
		printf("%s\r\n","SIO transmission error!");
		return SIOSERVICE_ERROR;
	}
	sio->txlen = 0;
	memset(sio->txque,0x00,BUF_MAX_LENGTH);
	USART1_TX.len = 0;
	memset(USART1_TX_BUF,0x00,BUF_MAX_LENGTH);
#endif
	return SIOSERVICE_OK;
}


